package com.ymx.darling.wrapper.fragment;

import com.ymx.darling.bean.entity.BeanInfo;
import com.ymx.darling.bean.entity.BeanInfoManager;
import com.ymx.darling.logicdelete.LogicDeleteManager;
import com.ymx.darling.tenant.TenantManager;
import com.ymx.darling.util.LambdaUtil;
import com.ymx.darling.util.StringUtil;
import com.ymx.darling.wrapper.QueryWrapper;
import com.ymx.darling.wrapper.fragment.lambda.LambdaGetter;
import com.ymx.darling.wrapper.fragment.lambda.WhereLambda;
import com.ymx.darling.bean.sql.SqlStatement;

import java.util.*;

/**
 * join片段
 * @author 爱Java的小于
 */
public class JoinSegment implements SqlSegment {
    public static final String JOIN = " JOIN ";
    public static final String LEFT_JOIN = " LEFT JOIN ";
    public static final String RIGHT_JOIN = " RIGHT JOIN ";

    private final List<String> tables = new LinkedList<>();
    private final LinkedList<Joiner> joiners = new LinkedList<>();

    @Override
    public SqlStatement getSqlStatement() {
        StringBuilder joinBuilder = new StringBuilder();
        List<Object> params = new ArrayList<>();
        joiners.forEach(joiner -> {
            SqlStatement joinSqlStatement = joiner.getSqlStatement();
            if (StringUtil.isNoNull(joinSqlStatement.getSql())) {
                joinBuilder.append(joinSqlStatement.getSql());
                params.addAll(joinSqlStatement.getParamList());
            }
        });
        return new SqlStatement(joinBuilder.toString(), params);
    }

    public List<Joiner> getJoins() {
        return this.joiners;
    }

    public Joiner join(String tableName, String joinType, QueryWrapper qw) {
        Joiner joiner = new Joiner(tableName, joinType, qw);
        this.joiners.add(joiner);
        this.tables.add(tableName);
        return joiner;
    }

    public List<String> getTables() {
        return this.tables;
    }

    /**
     * 封装join信息
     */
    public static class Joiner {
        private final String joinType;
        private final String tableName;
        private final QueryWrapper queryWrapper;
        private final List<Object> params = new LinkedList<>();
        private final WhereSegment whereSegment = new WhereSegment();

        public Joiner(String tableName, String joinType, QueryWrapper queryWrapper) {
            this.tableName = tableName;
            this.joinType = joinType;
            this.queryWrapper = queryWrapper;
        }

        public QueryWrapper on(WhereLambda whereCondition) {
            whereCondition.subWhere(this.whereSegment);
            return this.queryWrapper;
        }

        public QueryWrapper on(String tableOneColum, String tableTwoColum) {
            return this.on(on -> on.columnEq(tableOneColum, tableTwoColum));
        }

        public <L1,L2> QueryWrapper on(LambdaGetter<L1> table1Column, LambdaGetter<L2> table2Column) {
            return this.on(LambdaUtil.getColumnName(table1Column), LambdaUtil.getColumnName(table2Column));
        }

        public SqlStatement getSqlStatement() {
            // 判断添加逻辑删除，多租户条件
            if (BeanInfoManager.hasTable(this.tableName)) {
                BeanInfo joinBeanInfo = BeanInfoManager.getTableBeanInfo(this.tableName);
                if (LogicDeleteManager.isLogicDeleteEnabled(joinBeanInfo)) {
                    LogicDeleteManager.addConditionByWhere(joinBeanInfo.getLogicDeleteColumn(), this.tableName, this.whereSegment);
                }
                if (TenantManager.isTenantEnabled(joinBeanInfo)) {
                    TenantManager.addConditionByWhere(joinBeanInfo.getTenantIdColumn(), this.tableName, this.whereSegment);
                }
            }
            // 构建字符串
            StringBuilder joinBuilder = new StringBuilder();
            String currentTableName = BeanInfoManager.getCurrentTableName(this.tableName);
            joinBuilder.append(this.joinType).append(currentTableName);
            SqlStatement whereStatement = this.whereSegment.getSqlStatement();
            if (StringUtil.isNoNull(whereStatement.getSql())) {
                joinBuilder.append(" ON ").append(whereStatement.getSql());
                this.params.addAll(whereStatement.getParamList());
            }
            return new SqlStatement(joinBuilder.toString(), params);
        }
    }
}
